/*!
 * XQWizard v1.0.0
  
 * 创建人： 徐志强
 * http://www.mredcloud.com
 *
 * 根据麻省理工学院许可条款授权
 * https://gitee.com/jessyxu/JQueryWizard/blob/master/LICENSE
 */

;(function ($, window, document, undefined) {
    "use strict";
    // 默认选项

    var defaults = {
        selected: 0, // 最初选择的步骤 0, 0 = 第一步
        keyNavigation: true, // 启用/禁用键盘导航(如果启用，则使用左键和右键)
        autoAdjustHeight: true, //自动调整内容高度
        cycleSteps: false, // 允许循环导航的步骤
        backButtonSupport: true, // 启用后退按钮支持
        useURLhash: true, // 启用基于url哈希的步骤选择
        showStepURLhash: true, // 显示基于step的url哈希
        lang: { // 按钮语言变量
            next: '下一步',
            previous: '上一步'
        },
        toolbarSettings: {
            toolbarPosition: 'bottom', // none, top, bottom, both
            toolbarButtonPosition: 'end', // start, end
            showNextButton: true, // 显示/隐藏 下一步 按钮
            showPreviousButton: true, //  显示/隐藏 上一步 按钮
            toolbarExtraButtons: [] // 额外的按钮显示在工具栏上，jQuery输入/按钮元素数组
        },
        anchorSettings: {
            anchorClickable: true, // 启用/禁用锚导航
            enableAllAnchors: false, // 激活所有可点击的锚
            markDoneStep: true, // 添加完成css
            markAllPreviousStepsAsDone: true, // 当url哈希选择一个步骤时，所有前面的步骤都被标记为done
            removeDoneStepOnNavigateBack: false, // 而导航回来完成后，步骤后的活动将被清除
            enableAnchorOnDoneStep: true // 启用/禁用done steps导航
        },
        contentURL: null, // 内容url，支持Ajax内容加载。还可以在锚上设置为data- data-content-url、
        contentCache: true, // 缓存步骤内容，如果总是从ajax url获取假内容
        ajaxSettings: {}, // Ajax额外的设置
        disabledSteps: [], // 数组步骤禁用
        errorSteps: [], // 用错误突出显示步骤(高亮)
        hiddenSteps: [], // Hidden steps
        theme: 'default', // 主题为向导，相关css需要包含为其他默认主题
        transitionEffect: 'none', //导航效果，无/滑动/淡出, none/slide/fade
        transitionSpeed: '400'
    };

    //插件构造函数
    function XQWizard(element, options) {
        ///递归地将用户设置与默认值合并
        this.options = $.extend(true, {}, defaults, options);
        //主容器元素
        this.main = $(element);
        //导航栏元素
        this.nav = this.main.children('ul');
        //步进锚元素
        this.steps = $("li > a", this.nav);
        //内容容器
        this.container = this.main.children('div');
        // 内容页面
        this.pages = this.container.children('div');
        // 激活步骤索引
        this.current_index = null;

        // Backward compatibility
        this.options.toolbarSettings.toolbarButtonPosition = this.options.toolbarSettings.toolbarButtonPosition === 'right' ? 'end' : this.options.toolbarSettings.toolbarButtonPosition;
        this.options.toolbarSettings.toolbarButtonPosition = this.options.toolbarSettings.toolbarButtonPosition === 'left' ? 'start' : this.options.toolbarSettings.toolbarButtonPosition;

        // 默认 修复补丁主题
        this.options.theme = this.options.theme === null || this.options.theme === '' ? 'default' : this.options.theme;

        // 调用初始方法
        this.init();
    }
   
    $.extend(XQWizard.prototype, {

        init: function () {
            // 设置elements
            this._setElements();
            // 添加 toolbar
            this._setToolbar();
            // 指定插件的事件
            this._setEvents();

            var idx = this.options.selected;
            //从url中选择步骤
            if (this.options.useURLhash) {
                // 如果可用，从url哈希中获取步骤号
                var hash = window.location.hash;
                if (hash && hash.length > 0) {
                    var elm = $("a[href*='" + hash + "']", this.nav);
                    if (elm.length > 0) {
                        var id = this.steps.index(elm);
                        idx = id >= 0 ? id : idx;
                    }
                }
            }

            if (idx > 0 && this.options.anchorSettings.markDoneStep && this.options.anchorSettings.markAllPreviousStepsAsDone) {
                // 将活动步骤的前面步骤标记为已完成
                this.steps.eq(idx).parent('li').prevAll().addClass("done");
            }

            //显示初始步骤
            this._showStep(idx);
        },

        // 私有函数

        _setElements: function () {
            //设置主节点elements
            this.main.addClass('xq-main xq-theme-' + this.options.theme);
            // 这是锚定 elements
            this.nav.addClass('nav nav-tabs step-anchor').children('li').addClass('nav-item').children('a').addClass('nav-link'); // nav-justified  nav-pills

            // 让锚点可点击
            if (this.options.anchorSettings.enableAllAnchors !== false && this.options.anchorSettings.anchorClickable !== false) {
                this.steps.parent('li').addClass('clickable');
            }
            // 设置内容容器
            this.container.addClass('xq-container tab-content');
            // 设置内容页面
            this.pages.addClass('tab-pane step-content');

            // 禁用步骤
            var mi = this;
            if (this.options.disabledSteps && this.options.disabledSteps.length > 0) {
                $.each(this.options.disabledSteps, function (i, n) {
                    mi.steps.eq(n).parent('li').addClass('disabled');
                });
            }
            // 错误步骤
            if (this.options.errorSteps && this.options.errorSteps.length > 0) {
                $.each(this.options.errorSteps, function (i, n) {
                    mi.steps.eq(n).parent('li').addClass('danger');
                });
            }
            // 隐藏步骤  
            if (this.options.hiddenSteps && this.options.hiddenSteps.length > 0) {
                $.each(this.options.hiddenSteps, function (i, n) {
                    mi.steps.eq(n).parent('li').addClass('hidden');
                });
            }

            return true;
        },
        _setToolbar: function () {
            // 如果工具栏未启用，请立即跳过
            if (this.options.toolbarSettings.toolbarPosition === 'none') {
                return true;
            }

            // 创建工具栏按钮
            var btnNext = this.options.toolbarSettings.showNextButton !== false ? $('<button></button>').text(this.options.lang.next).addClass('btn btn-secondary xq-btn-next').attr('type', 'button') : null;
            var btnPrevious = this.options.toolbarSettings.showPreviousButton !== false ? $('<button></button>').text(this.options.lang.previous).addClass('btn btn-secondary xq-btn-prev').attr('type', 'button') : null;
            var btnGroup = $('<div></div>').addClass('btn-group mr-2 xq-btn-group').attr('role', 'group').append(btnPrevious, btnNext);

            // 添加额外的工具栏按钮
            var btnGroupExtra = null;

            if (this.options.toolbarSettings.toolbarExtraButtons && this.options.toolbarSettings.toolbarExtraButtons.length > 0) {
                btnGroupExtra = $('<div></div>').addClass('btn-group mr-2 xq-btn-group-extra').attr('role', 'group');
                $.each(this.options.toolbarSettings.toolbarExtraButtons, function (i, n) {
                    btnGroupExtra.append(n.clone(true));
                });
            }

            var toolbarTop, toolbarBottom;
            // 根据位置添加工具栏
            switch (this.options.toolbarSettings.toolbarPosition) {
                case 'top':
                    toolbarTop = $('<div></div>').addClass('btn-toolbar xq-toolbar xq-toolbar-top justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
                    toolbarTop.append(btnGroup);
                    if (this.options.toolbarSettings.toolbarButtonPosition === 'start') {
                        toolbarTop.prepend(btnGroupExtra);
                    } else {
                        toolbarTop.append(btnGroupExtra);
                    }
                    this.container.before(toolbarTop);
                    break;
                case 'bottom':
                    toolbarBottom = $('<div></div>').addClass('btn-toolbar xq-toolbar xq-toolbar-bottom justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
                    toolbarBottom.append(btnGroup);
                    if (this.options.toolbarSettings.toolbarButtonPosition === 'start') {
                        toolbarBottom.prepend(btnGroupExtra);
                    } else {
                        toolbarBottom.append(btnGroupExtra);
                    }
                    this.container.after(toolbarBottom);
                    break;
                case 'both':
                    toolbarTop = $('<div></div>').addClass('btn-toolbar xq-toolbar xq-toolbar-top justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
                    toolbarTop.append(btnGroup);
                    if (this.options.toolbarSettings.toolbarButtonPosition === 'start') {
                        toolbarTop.prepend(btnGroupExtra);
                    } else {
                        toolbarTop.append(btnGroupExtra);
                    }
                    this.container.before(toolbarTop);

                    toolbarBottom = $('<div></div>').addClass('btn-toolbar xq-toolbar xq-toolbar-bottom justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
                    toolbarBottom.append(btnGroup.clone(true));

                    if (btnGroupExtra !== null) {
                      if (this.options.toolbarSettings.toolbarButtonPosition === 'start') {
                          toolbarBottom.prepend(btnGroupExtra.clone(true));
                      } else {
                          toolbarBottom.append(btnGroupExtra.clone(true));
                      }
                    }
                    this.container.after(toolbarBottom);
                    break;
                default:
                    toolbarBottom = $('<div></div>').addClass('btn-toolbar xq-toolbar xq-toolbar-bottom justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
                    toolbarBottom.append(btnGroup);
                    if (this.options.toolbarSettings.toolbarButtonPosition === 'start') {
                        toolbarBottom.append(btnGroupExtra);
                    } else {
                        toolbarBottom.append(btnGroupExtra);
                    }
                    this.container.after(toolbarBottom);
                    break;
            }
            return true;
        },
        _setEvents: function () {
            // 锚点击事件
            var mi = this;
            $(this.steps).on("click", function (e) {
                e.preventDefault();
                if (mi.options.anchorSettings.anchorClickable === false) {
                    return true;
                }
                var idx = mi.steps.index(this);
                if (mi.options.anchorSettings.enableAnchorOnDoneStep === false && mi.steps.eq(idx).parent('li').hasClass('done')) {
                    return true;
                }

                if (idx !== mi.current_index) {
                    if (mi.options.anchorSettings.enableAllAnchors !== false && mi.options.anchorSettings.anchorClickable !== false) {
                        mi._showStep(idx);
                    } else {
                        if (mi.steps.eq(idx).parent('li').hasClass('done')) {
                            mi._showStep(idx);
                        }
                    }
                }
            });

            // 下一个按钮事件
            $('.xq-btn-next', this.main).on("click", function (e) {
                e.preventDefault();
                mi._showNext();
            });

            // 上一个按钮事件
            $('.xq-btn-prev', this.main).on("click", function (e) {
                e.preventDefault();
                mi._showPrevious();
            });

            // 键盘导航事件
            if (this.options.keyNavigation) {
                $(document).keyup(function (e) {
                    mi._keyNav(e);
                });
            }

            // 后退/前进 浏览器的按钮事件
            if (this.options.backButtonSupport) {
                $(window).on('hashchange', function (e) {
                    if (!mi.options.useURLhash) {
                        return true;
                    }
                    if (window.location.hash) {
                        var elm = $("a[href*='" + window.location.hash + "']", mi.nav);
                        if (elm && elm.length > 0) {
                            e.preventDefault();
                            mi._showStep(mi.steps.index(elm));
                        }
                    }
                });
            }

            return true;
        },
        _showNext: function () {
            var si = this.current_index + 1;
            //找到下一个未禁用的步骤
            for (var i = si; i < this.steps.length; i++) {
                if (!this.steps.eq(i).parent('li').hasClass('disabled') && !this.steps.eq(i).parent('li').hasClass('hidden')) {
                    si = i;
                    break;
                }
            }

            if (this.steps.length <= si) {
                if (!this.options.cycleSteps) {
                    return false;
                }
                si = 0;
            }
            this._showStep(si);
            return true;
        },
        _showPrevious: function () {
            var si = this.current_index - 1;
            // 找到前面的未禁用步骤
            for (var i = si; i >= 0; i--) {
                if (!this.steps.eq(i).parent('li').hasClass('disabled') && !this.steps.eq(i).parent('li').hasClass('hidden')) {
                    si = i;
                    break;
                }
            }
            if (0 > si) {
                if (!this.options.cycleSteps) {
                    return false;
                }
                si = this.steps.length - 1;
            }
            this._showStep(si);
            return true;
        },
        _showStep: function (idx) {
            // 如果没有找到步骤，跳过
            if (!this.steps.eq(idx)) {
                return false;
            }
            // 如果再次请求当前步骤，跳过
            if (idx == this.current_index) {
                return false;
            }
            // 如果这是一个禁用步骤，跳过
            if (this.steps.eq(idx).parent('li').hasClass('disabled') || this.steps.eq(idx).parent('li').hasClass('hidden')) {
                return false;
            }
            // 加载步骤内容
            this._loadStepContent(idx);
            return true;
        },
        _loadStepContent: function (idx) {
            var mi = this;
            // 获取当前步骤元素
            var curTab = this.steps.eq(this.current_index);
            // 得到步进导航的方向
            var stepDirection = '';
            var elm = this.steps.eq(idx);
            var contentURL = elm.data('content-url') && elm.data('content-url').length > 0 ? elm.data('content-url') : this.options.contentURL;

            if (this.current_index !== null && this.current_index !== idx) {
                stepDirection = this.current_index < idx ? "forward" : "backward";
            }

            // 触发“leaveStep”事件
            if (this.current_index !== null && this._triggerEvent("leaveStep", [curTab, this.current_index, stepDirection]) === false) {
                return false;
            }

            if (contentURL && contentURL.length > 0 && (!elm.data('has-content') || !this.options.contentCache)) {
                // 获取ajax内容，然后显示步骤
                var selPage = elm.length > 0 ? $(elm.attr("href"), this.main) : null;

                var ajaxSettings = $.extend(true, {}, {
                    url: contentURL,
                    type: "POST",
                    data: { step_number: idx },
                    dataType: "text",
                    beforeSend: function () {
                        mi._loader('show');
                    },
                    error: function (jqXHR, status, message) {
                        mi._loader('hide');
                        $.error(message);
                    },
                    success: function (res) {
                        if (res && res.length > 0) {
                            elm.data('has-content', true);
                            selPage.html(res);
                        }
                        mi._loader('hide');
                        mi._transitPage(idx);
                    }
                }, this.options.ajaxSettings);

                $.ajax(ajaxSettings);
            } else {
                // 显示步骤
                this._transitPage(idx);
            }
            return true;
        },
        _transitPage: function (idx) {
            var mi = this;
            // 获取当前步骤元素
            var curTab = this.steps.eq(this.current_index);
            var curPage = curTab.length > 0 ? $(curTab.attr("href"), this.main) : null;
            // 获取step来显示元素
            var selTab = this.steps.eq(idx);
            var selPage = selTab.length > 0 ? $(selTab.attr("href"), this.main) : null;
            // 得到步进导航的方向
            var stepDirection = '';
            if (this.current_index !== null && this.current_index !== idx) {
                stepDirection = this.current_index < idx ? "forward" : "backward";
            }

            var stepPosition = 'middle';
            if (idx === 0) {
                stepPosition = 'first';
            } else if (idx === this.steps.length - 1) {
                stepPosition = 'final';
            }

            this.options.transitionEffect = this.options.transitionEffect.toLowerCase();
            this.pages.finish();
            if (this.options.transitionEffect === 'slide') {
                // 正常 slide
                if (curPage && curPage.length > 0) {
                    curPage.slideUp('fast', this.options.transitionEasing, function () {
                        selPage.slideDown(mi.options.transitionSpeed, mi.options.transitionEasing);
                    });
                } else {
                    selPage.slideDown(this.options.transitionSpeed, this.options.transitionEasing);
                }
            } else if (this.options.transitionEffect === 'fade') {
                // 正常 fade
                if (curPage && curPage.length > 0) {
                    curPage.fadeOut('fast', this.options.transitionEasing, function () {
                        selPage.fadeIn('fast', mi.options.transitionEasing, function () {
                            $(this).show();
                        });
                    });
                } else {
                    selPage.fadeIn(this.options.transitionSpeed, this.options.transitionEasing, function () {
                        $(this).show();
                    });
                }
            } else {
                if (curPage && curPage.length > 0) {
                    curPage.hide();
                }
                selPage.show();
            }
            // 将url散列更改为new step
            this._setURLHash(selTab.attr("href"));
            // 更新控制
            this._setAnchor(idx);
            // 根据步骤设置按钮
            this._setButtons(idx);
            // 固定高度与内容
            this._fixHeight(idx);
            // 更新当前索引
            this.current_index = idx;

            // 触发“showStep”事件
            this._triggerEvent("showStep", [selTab, this.current_index, stepDirection, stepPosition]);
            return true;
        },
        _setAnchor: function (idx) {
            //当前 步骤锚定>删除其他类 并添加done类
            this.steps.eq(this.current_index).parent('li').removeClass("active");
            if (this.options.anchorSettings.markDoneStep !== false && this.current_index !== null) {
                this.steps.eq(this.current_index).parent('li').addClass("done");
                if (this.options.anchorSettings.removeDoneStepOnNavigateBack !== false) {
                    this.steps.eq(idx).parent('li').nextAll().removeClass("done");
                }
            }

            // 下一步锚定>删除其他类并添加活动类
            this.steps.eq(idx).parent('li').removeClass("done").addClass("active");
            return true;
        },
        _setButtons: function (idx) {
            // 上/下 按钮 启用/禁用  基于步骤
            if (!this.options.cycleSteps) {
                if (0 >= idx) {
                    $('.xq-btn-prev', this.main).addClass("disabled");
                } else {
                    $('.xq-btn-prev', this.main).removeClass("disabled");
                }
                if (this.steps.length - 1 <= idx) {
                    $('.xq-btn-next', this.main).addClass("disabled");
                } else {
                    $('.xq-btn-next', this.main).removeClass("disabled");
                }
            }
            return true;
        },

        // 辅助函数

        _keyNav: function (e) {
            var mi = this;
            // 键盘导航
            switch (e.which) {
                case 37:
                    // 左
                    mi._showPrevious();
                    e.preventDefault();
                    break;
                case 39:
                    // 右
                    mi._showNext();
                    e.preventDefault();
                    break;
                default:
                    return; //  退出此处理程序以获取其他键盘按键
            }
        },
        _fixHeight: function (idx) {
            // 自动调整容器高度
            if (this.options.autoAdjustHeight) {
                var selPage = this.steps.eq(idx).length > 0 ? $(this.steps.eq(idx).attr("href"), this.main) : null;
                this.container.finish().animate({ minHeight: selPage.outerHeight() }, this.options.transitionSpeed, function () {});
            }
            return true;
        },
        _triggerEvent: function (name, params) {
            // 触发一个事件
            var e = $.Event(name);
            this.main.trigger(e, params);
            if (e.isDefaultPrevented()) {
                return false;
            }
            return e.result;
        },
        _setURLHash: function (hash) {
            if (this.options.showStepURLhash && window.location.hash !== hash) {
                window.location.hash = hash;
            }
        },
        _loader: function (action) {
            switch (action) {
                case 'show':
                    this.main.addClass('xq-loading');
                    break;
                case 'hide':
                    this.main.removeClass('xq-loading');
                    break;
                default:
                    this.main.toggleClass('xq-loading');
            }
        },

        // 公共函数

        theme: function (v) {
            if (this.options.theme === v) {
                return false;
            }
            this.main.removeClass('xq-theme-' + this.options.theme);
            this.options.theme = v;
            this.main.addClass('xq-theme-' + this.options.theme);
            // Trigger "themeChanged" event
            this._triggerEvent("themeChanged", [this.options.theme]);
        },
        next: function () {
            this._showNext();
        },
        prev: function () {
            this._showPrevious();
        },
        reset: function () {
            // 触发“beginReset”事件
            if (this._triggerEvent("beginReset") === false) {
                return false;
            }

            // 重置所有元素和类
            this.container.stop(true);
            this.pages.stop(true);
            this.pages.hide();
            this.current_index = null;
            this._setURLHash(this.steps.eq(this.options.selected).attr("href"));
            $(".xq-toolbar", this.main).remove();
            this.steps.removeClass();
            this.steps.parents('li').removeClass();
            this.steps.data('has-content', false);
            this.init();

            // 触发“endReset”事件
            this._triggerEvent("endReset");
        },
        stepState: function (stepArray, state) {
            var mi = this;
            stepArray = $.isArray(stepArray) ? stepArray : [stepArray];
            var selSteps = $.grep(this.steps, function (n, i) {
                return $.inArray(i, stepArray) !== -1; //  && i !== mi.current_index
            });
            if (selSteps && selSteps.length > 0) {
                switch (state) {
                    case 'disable':
                        $(selSteps).parents('li').addClass('disabled');
                        break;
                    case 'enable':
                        $(selSteps).parents('li').removeClass('disabled');
                        break;
                    case 'hide':
                        $(selSteps).parents('li').addClass('hidden');
                        break;
                    case 'show':
                        $(selSteps).parents('li').removeClass('hidden');
                        break;
                    case 'error-on':
                        $(selSteps).parents('li').addClass('danger');
                        break;
                    case 'error-off':
                        $(selSteps).parents('li').removeClass('danger');
                        break;
                }
            }
        }
    });

    // 插件的包装器
    $.fn.xqWizard = function (options) {
        var args = arguments;
        var instance;

        if (options === undefined || typeof options === 'object') {
            return this.each(function () {
                if (!$.data(this, "xqWizard")) {
                    $.data(this, "xqWizard", new XQWizard(this, options));
                }
            });
        } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
            instance = $.data(this[0], 'xqWizard');

            if (options === 'destroy') {
                $.data(this, 'xqWizard', null);
            }

            if (instance instanceof XQWizard && typeof instance[options] === 'function') {
                return instance[options].apply(instance, Array.prototype.slice.call(args, 1));
            } else {
                return this;
            }
        }
    };
})(jQuery, window, document);
